
// Copyright (C) 2011 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef _DERM_SIMD_H_
#define _DERM_SIMD_H_

/* === Operations types =======================================================
 * 
 * - Single: two single operands
 * - Batch: multiple left operands, one right operand
 * - Stream: multiple left and right operands
 *
 *  * Result storage
 *
 * Note that all operations type shall allow to store result in different
 * memory segments from 'left' operand. In the case callee want to store
 * results in the left operand, they could specify the same argument for result
 * and left operand.
 *
 *  * Batch and Stream peculiarities
 *
 * It is desiderable that 'Batch' and 'Stream' operations are based on 'Single'
 * implementation by inlining a separate routine, but whenever it is possible
 * to pack multiple operations among the available registers, the 'Single'
 * implementation won't be used by 'Batch' and 'Stream' implementations.
 *
 *  * Memory alignment
 *
 * It is desiderable that 'Batch' and 'Stream' operations are based on 'Single'
 * implementation by inlining a separate routine, but 'Batch' and 'Stream'
 * implementations would load data differently depending on memory alignment.
 *
 * This would imply different implementation of the 'Single' operation,
 * depending on input and output memory alignment.
 *
 * === Operations =============================================================
 * 
 * - Vector3 by scalar multiplication (Single, Batch, Stream)
 * - Vector3 by Vector3 addition (Single, Batch, Stream)
 * - Vector3 by Matrix4x4 multiplication (Single, Batch, Stream)
 * 
 * - Vector4 by scalar multiplication (Single, Batch, Stream)
 * - Vector4 by Vector4 addition (Single, Batch, Stream)
 * - Vector4 by Matrix4x4 multiplication (Single, Batch, Stream)
 *
 * - Matrix4x4 by Matrix4x4 multiplication  (Single, Batch, Stream)
 *
 * === Function Conventions ===================================================
 *
 * A function name is conventionally composed using the following uniform
 * patterns:
 *
 * - Unary function: <Type>_<Operation>_<OperationType>[_<InstructionSet>]
 * - Binary function: <Type>_<Operation>_<Type>_<OperationType>[_<InstructionSet>]
 *
 * Also signature are uniforms:
 * - Unary function (<OperationType> == Single): void <FunctionName>(<TypeBase> *dst, <TypeBase> *src)
 *		- dst: destination of the operation data
 *		- src: source data for the operation
 * 
 * - Unary function (<OperationType> != Single): void <FunctionName>(<TypeBase> *dstVector, <TypeBase> *srcVector, unsigned int count)
 * - Binary function (<OperationType> == Single): void <FunctionName>(<TypeBase> *dst, <TypeBase> *left, <TypeBase> *right)
 * - Binary function (<OperationType> != Single): void <FunctionName>(<TypeBase> *dstVector, <TypeBase> *leftVector, <TypeBase> *rightVector, unsigned int count)
 * 
 *
 * - Available <Type> values are
 *		- Vector3
 *		- Vector4
 *		- Matrix4x4
 * - Available <Operation> values are
 *		- Add
 *		- Multiply
 * - Available <OperationType> values are
 *		- Single
 *		- Batch
 *		- Stream
 * - Available <InstructionSet> values are:
 *		- MMX
 *		- 3DNOW
 *		- SSE
 *		- SSE2
 *		- SSE3
 *		- SSSE3
 *		- None (C implementation)
 */

#ifdef WIN32

#define DERM_SIMD_EXPORT		__declspec(dllexport)

#define DERM_SIMD_API			__cdecl

#else

#define DERM_SIMD_EXPORT

#define DERM_SIMD_API

#endif

#ifdef __cplusplus
extern "C" {
#endif

	//=== CPU Information ========================================================

	/** Processor type enumeration type definition.
	  */
	typedef enum _ProcessorType
	{
		ProcessorTypeOEM =				0x00,
		ProcessorTypeOverdriver =		0x01,
		ProcessorTypeDual =				0x02,
		ProcessorTypeReserved =			0x03
	} ProcessorType;

	/** SIMD technologies supported by the CPU.
	  */
	typedef enum _SimdTecnology
	{
		SIMD_MMX =		0x00000001,
		SIMD_SSE =		0x00000002,
		SIMD_SSE2 =		0x00000004,
		SIMD_SSE3 =		0x00000008,
		SIMD_SSSE3 =	0x00000010,
		SIMD_SSE4 =		0x00000020,
		SIMD_AVX =		0x00000100,
		SIMD_3DNow =	0x00010000,
		SIMD_3DNow2 =	0x00020000,
	} SimdTecnology;

	/** Other technologies supported by the CPU.
	  */
	typedef enum _OtherTechnology
	{
		/** TSC timer.
		  */
		OTHER_TSC =		0x00000001,
	} OtherTechnology;

	/** Type used for masking multiple tecnologies.
	  */
	typedef unsigned int TecnologyMask;

#pragma pack push 4

	/** CPU information.
	  */
	typedef struct _CpuInfo
	{
		/** Vendor name.
		  */
		char Vendor[13];

		/** CPU type.
		  */
		int ProcessorType;

		/** CPU family.
		  */
		int Family;

		/** CPU family extended.
		  */
		int FamilyExtended;

		/** CPU model.
		  */
		int Model;

		/** CPU model extended.
		  */
		int ModelExtended;

		/** CPU stepping.
		  */
		int Stepping;

		/** SIMD tecnologies actually supported.
		  */
		TecnologyMask SimdSupport;

		/** Other tecnologies actually supported.
		  */
		TecnologyMask OtherSupport;

	} CpuInfo;

#pragma pack pop

	/** Get current CPU information.
	  */
	DERM_SIMD_EXPORT void DERM_SIMD_API GetCpuInformation(CpuInfo *cpuInfo);

	//=== Vector Operations ===================================================



	//=== Matrix Operations ===================================================

	/** Multiplication between Matrix4x4 and Matrix4x4, using C implementation.
	  *
	  * @paran result		Operation result.
	  * @param left			Operation left operand.
	  * @param right		Operation right operand.
	  */
	DERM_SIMD_EXPORT void DERM_SIMD_API Matrix4x4_Multiply_Matrix4x4(float *result, float *left, float *right);
	
	/** Multiplication between Matrix4x4 and Matrix4x4, using SSE extension.
	  *
	  * @paran result		Operation result.
	  * @param left			Operation left operand.
	  * @param right		Operation right operand.
	  */
	DERM_SIMD_EXPORT void DERM_SIMD_API Matrix4x4_Multiply_Matrix4x4_SSE(float *result, float *left, float *right);

	/** Concatenate (multiply) a vector of Matrix4x4, using C implementation.
	  *
	  * @param matrices		Vector of matrices.
	  * @param count		The left of the vector of matrices.
	  */
	DERM_SIMD_EXPORT void DERM_SIMD_API Matrix4x4_Concatenate(float *matrices[], unsigned int count);

	/** Concatenate (multiply) a vector of Matrix4x4, using SSE extension.
	  *
	  * @param matrices		Vector of matrices.
	  * @param count		The left of the vector of matrices.
	  */
	DERM_SIMD_EXPORT void DERM_SIMD_API Matrix4x4_Concatenate_SSE(float *matrices[], unsigned int count);

	//=== Memory Operations ===================================================

	/** Copy a memory to another memory.
	  *
	  * @param dst		Destination memory.
	  * @param src		Source memory.
	  * @param bytes	Number of bytes to copy from 'src' to 'dst'.
	  */
	DERM_SIMD_EXPORT void DERM_SIMD_API Memory_Copy_SSE2(void *dst, void *src, unsigned long long bytes);

#ifdef __cplusplus
}
#endif

#endif /* _DERM_SIMD_H_ */

